;;;;

(in-package :lib.gl)

(use-package :fiveam)

(test test-glpointer
      (let* ((ptr (%gl-vector 4 3 2 1))
             (p2 (%gl-vector 4 3 2 1))
             (a1 (make-gl-array '(2 2) :initial-contents '((1.0 0.0) (0.0 1.0))))
             (a2 (make-gl-array '(3 3) :initial-contents '((1.0 2.0 3.0) (4.0 5.0 6.0) (7.0 8.0 9.0))))
             (a3 (make-gl-array '(3 3) :initial-contents '((1.0 2.0 3.0) (4.0 5.0 6.0) (7.0 8.0 9.0)))))
        (is (eql (slot-value ptr 'element-type) (type-of 4)))
        (is (eql (slot-value ptr 'element-count) 4))
        (is (equalp (slot-value ptr 'ivector) #(4 3 2 1)))
        (is (eql (slot-value ptr 'dims) 4))
        (is (eql (gl-vector-length ptr) 4))
        (is (= (gl-aref ptr 2) 2))
        (is (= (gl-aref ptr 3) 1))
        (is (gl-array-equal ptr p2))
        (is (not (gl-array-equal a1 a2)))
        (is (gl-array-equal a2 a3))))

;(stefil:in-suite test-vector-math)

(test test-quaternions
  (let* ((quat (%gl-vector 0.0 0.0 0.0 1.0))
	 (not-quat (%gl-vector 1.0 1.0 1.0))
         (f (sqrt 0.5))
         (q90x (%gl-vector f f 0 0))
         (q90y (%gl-vector f 0 f 0))
         (q90z (%gl-vector f 0 0 f))
	 (rot90z (make-square-matrix 0.0 -1.0 0.0 0.0
                                     1.0 0.0 0.0 0.0
                                     0.0 0.0 1.0 0.0
                                     0.0 0.0 0.0 1.0)))
    (is (typep quat 'quaternion))
    (is (not (typep not-quat 'quaternion)))))

(test test-vectors
  ;; Just call all the functions and make sure Lisp doesn't dump.
  (let* ((vec0 (zero-vector 3))
	 (vec-x (unit-x-vector))
	 (vec-y (unit-y-vector))
	 (vec-z (unit-z-vector))
	 (vec-sum (%gl-vector 1.0 1.0 1.0))
	 (vec-w (unit-w-vector)))
    (is (vector= vec-x (unit-x-vector)))
    (is (not (vector= vec-x vec0)))
    (is (vector3-p vec0))
    (is (not (vector2-p vec0)))
    (is (= (x vec-x) 1.0))
    (is (= (y vec-y) 1.0))
    (is (= (z vec-z) 1.0))
    (setf (x vec0) 1.0)
    (setf (y vec0) 1.0)
    (setf (z vec0) 1.0)
    (is (vector= vec0 vec-sum))
    (is (vector= (m+ vec-x vec-y vec-z) vec-sum))
    (is (vector= (m- vec-sum vec-sum) (zero-vector 3)))
    (is (vector= (m* 3.0 vec-sum) (%gl-vector 3.0 3.0 3.0)))
    (is (vector= (m/ (%gl-vector 3.0 3.0 3.0) 3.0) vec-sum))
    (is (vector= (mneg (unit-x-vector)) (%gl-vector -1.0 0.0 0.0)))
    (is (= (magnitude (%gl-vector 2.0 2.0)) (sqrt 8.0)))
    (is (= (squared-magnitude (%gl-vector 2.0 2.0)) 8.0))
    (is (= (dot-product (%gl-vector 1.0 1.0 1.0)
			       (%gl-vector 1.0 1.0 1.0))
		  3.0))))

(test test-matrix
      (let* ((m0 (make-square-matrix 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0))
             (m1 (identity-matrix 3)))
        (is (matrix-equal m0 (zero-matrix 3)))
        (is (not (matrix-equal m0 m1)))))
             
(test test-vector-math
      (let* ((vec2d (%gl-vector 1.0 0.0))
             (vec2d-perp (perp vec2d)))
        ;; Using Pythagoras formula to test if two vectors are perpendicular.
        (is (= (+ (squared-magnitude vec2d) (squared-magnitude vec2d-perp))
               (squared-magnitude (m- vec2d vec2d-perp))))
        (is (vector= (normalize (%gl-vector 1.0 0.0 1.0))
                     (%gl-vector (/ 1 (sqrt 2)) 0.0 (/ 1 (sqrt 2)))))
        (is (vector= (cross (unit-x-vector) (unit-y-vector)) (unit-z-vector)))
        (is (vector= (cross (%gl-vector 2.0 1.0 -1.0)
                            (%gl-vector -3.0 4.0 1.0))
                     (%gl-vector 5.0 1.0 11.0)))
        (multiple-value-bind (u0 u1 u2) (orthonormalize (%gl-vector 1.0 0.0 1.0)
                                                        (%gl-vector 1.0 0.0 0.0)
                                                        (%gl-vector 2.0 1.0 0.0))
          (is (vector= u0 (m/ (%gl-vector 1.0 0.0 1.0)
                              (sqrt 2.0))))
          (is (vector= u1 (m/ (%gl-vector 1.0 0.0 -1.0)
                              (sqrt 2.0)))))))

(test test-physics
      )